/*
 *  $Id: PhraseTemplateScanner.cs 1179 2010-11-10 12:29:24Z thenn.erannor $
 *	This file is a part of Ragima CCG.
 *	(C) 2008-2010 Ragima development group.
 *
 *	Licensed under the terms of the GNU GPL License version 2.
 *
 */

using System;

namespace Ragima.Languages {
    /// <summary>
    /// Сканер для чтения и разбора шаблона фразы.
    /// </summary>
    public class PhraseTemplateScanner {
        private string _template;
        private int _pos, _len;

        public PhraseTemplateScanner(string template) {
            _template = template;
            _pos = 0;
            _len = _template.Length;
        }

        /// <summary>
        /// Текущая позиция курсора чтения.
        /// </summary>
        public int Position {
            get { return _pos; }
            set {
                if (value < 0)
                    _pos = 0;
                else if (value > _len)
                    _pos = _len;
                else
                    _pos = value;
            }
        }

        /// <summary>
        /// Стоит ли курсор чтения в конце шаблона.
        /// </summary>
        public bool IsEnd {
            get { return _pos >= _len; }
        }

        /// <summary>
        /// Символ в текущей позиции курсора чтения.
        /// </summary>
        public char Current {
            get { return IsEnd ? PhraseTemplateSymbols.DefaultChar : _template[_pos]; }
        }

        /// <summary>
        /// Стоит ли курсор чтения на начале команды.
        /// </summary>
        public bool IsCommand {
            get { return Current == PhraseTemplateSymbols.CommandStart; }
        }

        /// <summary>
        /// Стоит ли курсор чтения на цифре.
        /// </summary>
        public bool IsNumber {
            get { return char.IsDigit(Current); }
        }

        /// <summary>
        /// Перемещает курсор чтения на 1 символ вперед.
        /// </summary>
        public void NextChar() {
            if (!IsEnd)
                _pos++;
        }

        /// <summary>
        /// Перемещает курсор чтения до указанного символа, либо до конца шаблона, если такого символа нет.
        /// </summary>
        /// <param name="end">
        /// A <see cref="System.Char"/>
        /// </param>
        public void SkipTo(char end) {
            while (!IsEnd && Current != end)
                NextChar();
        }

        /// <summary>
        /// Перемещает курсор чтения до следующего за командой символа.
        /// </summary>
        public void SkipCommand() {
            if (IsCommand)
                NextChar();
            SkipTo(PhraseTemplateSymbols.CommandEnd);
            NextChar();
        }

        /// <summary>
        /// Получает символ в позиции курсора чтения и перемещает курсор вперед.
        /// </summary>
        public char GetChar() {
            var ch = Current;
            NextChar();
            return ch;
        }

        /// <summary>
        /// Проверяет, равен ли указанный символ текущему.
        /// </summary>
        public bool Test(char test) {
            return Current == test;
        }

        /// <summary>
        /// Проверяет, равен ли указанный символ текущему, без учета регистра символов.
        /// </summary>
        public bool TestIgnoreCase(char test) {
            return char.ToLower(Current) == char.ToLower(test);
        }

        /// <summary>
        /// Получает текст из шаблона от текущей позиции до начала команды, перемещая так же курсор.
        /// </summary>
        public string GetText() {
            int start = _pos;
            SkipTo(PhraseTemplateSymbols.CommandStart);
            return _pos > start ? _template.Substring(start, _pos - start) : string.Empty;
        }

        /// <summary>
        /// Получает текст из шаблона от текущей позиции до конца команды, перемещая так же курсор.
        /// </summary>
        public string GetCommandText() {
            int start = _pos;
            SkipTo(PhraseTemplateSymbols.CommandEnd);
            return _pos > start ? _template.Substring(start, _pos - start) : string.Empty;
        }

        /// <summary>
        /// Получает число в текущей позиции, перемещая курсор на следующий за числом символ.
        /// </summary>
        public int GetNumber() {
            if (!IsNumber)
                return default(int);
            int start = _pos;
            do { NextChar(); } while (IsNumber);
            return int.Parse(_template.Substring(start, _pos - start));
        }

        /// <summary>
        /// Получает значение перечислимого типа по числу в текущей позиции.
        /// </summary>
        public T GetEnum<T>() {
            var values = Enum.GetValues(typeof(T));
            var i = GetNumber();
            return (i >= 0 && i < values.Length) ? (T) values.GetValue(i) : default(T);
        }
    }
}
